package com.foreveross.util;

import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HttpClientUtil {
	
	private static Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);
	
	private DefaultHttpClient httpClient;

	private int maxConLifeTimeMs = 60000;
	private int defaultMaxConPerHost = 500;
	private int maxTotalConn = 1000;
	private int conTimeOutMs = 3000;
	private int soTimeOutMs = 3000;


	public static HttpClientUtil getInstance() throws Exception {
		return new HttpClientUtil(80, 443);
	}

	public static HttpClientUtil getInstance(int httpProt) throws Exception {
		return new HttpClientUtil(httpProt, 443);
	}

	public static HttpClientUtil getInstance(int httpProt, int SSLPort)
			throws Exception {
		return new HttpClientUtil(httpProt, SSLPort);
	}

	private HttpClientUtil(int httpProt, int SSLPort) throws Exception {
		SSLContext ctx = null;
		try {
			ctx = SSLContext.getInstance("TLS");
			X509TrustManager tm = new X509TrustManager() {
				public void checkClientTrusted(X509Certificate[] xcs,
						String string) throws CertificateException {
				}

				public void checkServerTrusted(X509Certificate[] xcs,
						String string) throws CertificateException {
				}

				public X509Certificate[] getAcceptedIssuers() {
					return null;
				}
			};
			ctx.init(null, new TrustManager[] { tm }, null);
		} catch (Exception e) {
			throw e;
		}
		SSLSocketFactory ssf = new SSLSocketFactory(ctx,
				SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
		SchemeRegistry schemeRegistry = new SchemeRegistry();
		schemeRegistry.register(new Scheme("http", httpProt, PlainSocketFactory
				.getSocketFactory()));
		schemeRegistry.register(new Scheme("https", SSLPort, ssf));

		ThreadSafeClientConnManager connectionManager = new ThreadSafeClientConnManager(
				schemeRegistry, maxConLifeTimeMs, TimeUnit.MILLISECONDS);
		connectionManager.setMaxTotal(maxTotalConn);
		connectionManager.setDefaultMaxPerRoute(defaultMaxConPerHost);
		httpClient = new DefaultHttpClient(connectionManager);
		httpClient.getParams().setParameter(
				CoreConnectionPNames.CONNECTION_TIMEOUT, conTimeOutMs);
		httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT,
				soTimeOutMs);
	}

	/**
	 * 反回状态码
	 * 
	 * @param url
	 *            请求地址
	 * 
	 * @return 响应头状态码
	 * @throws Exception
	 */
	public int execute(String url) throws Exception {
		HttpClient httpClient = null;
		HttpResponse response = null;
		HttpPost post = new HttpPost(url);
		post.setHeader("Connection", "close");

		try {
			httpClient = HttpClientUtil.getInstance().httpClient;
			response = httpClient.execute(post);

			return response.getStatusLine().getStatusCode();
		} catch (Exception e) {
			throw e;
		} finally {
			httpClient.getConnectionManager().shutdown(); // 关闭连接,释放资源
		}
	}
	
	public String executeByGet(String url) throws Exception {
		HttpClient httpClient = null;
		HttpResponse response = null;
		HttpGet get = new HttpGet(url);
		get.setHeader("Connection", "close");

		try {
			httpClient = HttpClientUtil.getInstance().httpClient;
			response = httpClient.execute(get);
			logger.debug("请求相应码: {}", response.getStatusLine().getStatusCode());
			return EntityUtils.toString(response.getEntity(), "utf-8");
		} catch (Exception e) {
			throw e;
		} finally {
			httpClient.getConnectionManager().shutdown(); // 关闭连接,释放资源
		}
	}

	public Map<String, String> login(String url, Map<String, String> params,
			Map<String, String> headerMap,String encoding) {
		HttpPost post = null;
		HttpResponse response = null;
		HttpEntity entity = null;
		HttpEntity uefEntity = null;
		int size = 2;
		int index = 0;
		Header[] headers = null;
		// 设置需要提交的参数
		List<NameValuePair> list = new ArrayList<NameValuePair>();
		Map<String, String> result = new HashMap<String, String>();

		if (headerMap == null) {
			headers = new Header[size];
		} else {
			size += headerMap.size();
			headers = new Header[size];
			Set<Entry<String, String>> entrySet = headerMap.entrySet();

			for (Entry<String, String> entry : entrySet) {
				headers[index++] = new BasicHeader(entry.getKey(),
						entry.getValue());
			}
		}

		if (params != null){
			for (Entry<String, String> entry : params.entrySet()) {
				list.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
			}
		}

		headers[index++] = new BasicHeader("User-Agent",
				"Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1");
		headers[index] = new BasicHeader("Connection", "close");

		try {
			uefEntity = new UrlEncodedFormEntity(list, encoding);
			post = new HttpPost(url);
			post.setEntity(uefEntity);
			post.setHeaders(headers);
			response = httpClient.execute(post);
			result.put("cookie", assemblyCookie(httpClient.getCookieStore()
					.getCookies()));
			entity = response.getEntity(); // 获取响应实体
			if (null != entity) {
				result.put("content", EntityUtils.toString(entity, encoding));
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				EntityUtils.consume(entity);
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				httpClient.getConnectionManager().shutdown(); // 关闭连接,释放资源
			}
		}

		return result;
	}

	// 这是组装cookie
	public String assemblyCookie(List<Cookie> cookies) {
		StringBuffer sbu = new StringBuffer();
		for (Cookie cookie : cookies) {
			sbu.append(cookie.getName()).append("=").append(cookie.getValue())
					.append(";");
		}
		if (sbu.length() > 0)
			sbu.deleteCharAt(sbu.length() - 1);
		return sbu.toString();
	}

	public String execute(String url, Map<String, String> params, Map<String, String> headerMap ,String encoding) throws Exception {
		String result = null;
		HttpPost post = null;
		HttpResponse response = null;
		HttpEntity entity = null;
		HttpEntity uefEntity = null;
		int size = 2;
		int index = 0;
		Header[] headers = null;
		// 设置需要提交的参数
		List<NameValuePair> paramsList = new ArrayList<NameValuePair>();

		if (headerMap == null) {
			headers = new Header[size];
		} else {
			size += headerMap.size();
			headers = new Header[size];
			Set<Entry<String, String>> entrySet = headerMap.entrySet();

			for (Entry<String, String> entry : entrySet) {
				headers[index++] = new BasicHeader(entry.getKey(),
						entry.getValue());
			}
		}
		
		if (params != null){
			for (Entry<String, String> entry : params.entrySet()) {
				paramsList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
			}
		}

		int versionMain = (int) (Math.random() * 10);
		int version = (int) (Math.random() * 10);

		headers[index++] = new BasicHeader("User-Agent",
				"Mozilla/5.0 (Windows NT 5.2; rv:" + versionMain + "."
						+ version + ".1) Gecko/20100101 Firefox/" + versionMain
						+ "." + version + ".1");
		headers[index] = new BasicHeader("Connection", "close");

		try {
			logger.debug("请求的URL：{}", url);
			uefEntity = new UrlEncodedFormEntity(paramsList, encoding);
			post = new HttpPost(url);
			post.setEntity(uefEntity);
			post.setHeaders(headers);
			response = httpClient.execute(post);
			entity = response.getEntity(); // 获取响应实体
			if (null != entity) {
				result = EntityUtils.toString(entity, encoding);
			}
			
			logger.debug("请求相应码: {}\t\t, 响应类容：{}", response.getStatusLine().getStatusCode(), result);

		} catch(org.apache.http.conn.ConnectTimeoutException cte) {
			logger.error("请求异常,url:" + url + "  参数为:" + params.toString());
			logger.error(cte.getMessage());
			throw cte;
		} catch (Exception e) {
			logger.error("请求异常,url:" + url + "  参数为:" + params.toString());
			logger.error("异常原因:" + e.getMessage());
		} finally {
			try {
				EntityUtils.consume(entity);
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				httpClient.getConnectionManager().shutdown(); // 关闭连接,释放资源
			}
		}

		return result;
	}
	
	public void setProxy(HttpHost proxy){
		httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
	}
	public String execute(String url,Map<String, String> headerMap,String json, String encoding) {
		String result = null;
		HttpPost post = null;
		HttpResponse response = null;
		HttpEntity entity = null;
		StringEntity uefEntity = null;
		int size = 2;
		int index = 0;
		Header[] headers = null;

		int versionMain = (int) (Math.random() * 10);
		int version = (int) (Math.random() * 10);

		if (headerMap == null) {
			headers = new Header[size];
		} else {
			size += headerMap.size();
			headers = new Header[size];
			Set<Entry<String, String>> entrySet = headerMap.entrySet();

			for (Entry<String, String> entry : entrySet) {
				headers[index++] = new BasicHeader(entry.getKey(),
						entry.getValue());
			}
		}
		
		headers[index++] = new BasicHeader("User-Agent",
				"Mozilla/5.0 (Windows NT 5.2; rv:" + versionMain + "."
						+ version + ".1) Gecko/20100101 Firefox/" + versionMain
						+ "." + version + ".1");
		headers[index] = new BasicHeader("Connection", "close");

		try {
			uefEntity =  new StringEntity(json);
			uefEntity.setContentEncoding(encoding);  
			uefEntity.setContentType("application/json"); 
			post = new HttpPost(url);
			post.setEntity(uefEntity);
			post.setHeaders(headers);
			response = httpClient.execute(post);
			entity = response.getEntity(); // 获取响应实体
			if (null != entity) {
				result = EntityUtils.toString(entity, encoding);
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				EntityUtils.consume(entity);
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				httpClient.getConnectionManager().shutdown(); // 关闭连接,释放资源
			}
		}

		return result;
	}

}
